﻿using System;

namespace Net35.Xrm.Sdk
{
	#region Static Tuple Class
	internal static class Tuple
	{
		public static Tuple<T1> Create<T1>(T1 item1)
		{
			return new Tuple<T1>(item1);
		}
		public static Tuple<T1, T2> Create<T1, T2>(T1 item1, T2 item2)
		{
			return new Tuple<T1, T2>(item1, item2);
		}
		public static Tuple<T1, T2, T3> Create<T1, T2, T3>(T1 item1, T2 item2, T3 item3)
		{
			return new Tuple<T1, T2, T3>(item1, item2, item3);
		}
		public static Tuple<T1, T2, T3, T4> Create<T1, T2, T3, T4>(T1 item1, T2 item2, T3 item3, T4 item4)
		{
			return new Tuple<T1, T2, T3, T4>(item1, item2, item3, item4);
		}
		public static Tuple<T1, T2, T3, T4, T5> Create<T1, T2, T3, T4, T5>(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5)
		{
			return new Tuple<T1, T2, T3, T4, T5>(item1, item2, item3, item4, item5);
		}
		public static Tuple<T1, T2, T3, T4, T5, T6> Create<T1, T2, T3, T4, T5, T6>(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6)
		{
			return new Tuple<T1, T2, T3, T4, T5, T6>(item1, item2, item3, item4, item5, item6);
		}
		public static Tuple<T1, T2, T3, T4, T5, T6, T7> Create<T1, T2, T3, T4, T5, T6, T7>(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6, T7 item7)
		{
			return new Tuple<T1, T2, T3, T4, T5, T6, T7>(item1, item2, item3, item4, item5, item6, item7);
		}
		public static Tuple<T1, T2, T3, T4, T5, T6, T7, TRest> Create<T1, T2, T3, T4, T5, T6, T7, TRest>(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6, T7 item7, TRest rest)
		{
			return new Tuple<T1, T2, T3, T4, T5, T6, T7, TRest>(item1, item2, item3, item4, item5, item6, item7, rest);
		}

		internal static bool EqualTupleFieldValues<T>(T one, T two)
		{
			if (one == null && two == null) return true;
			if (one == null || two == null) return false;
			return one.Equals(two);
		}

		#region HashCodes
		internal static int CombineHashCodes(int h1, int h2)
		{
			return (h1 << 5) + h1 ^ h2;
		}
		internal static int CombineHashCodes(int h1, int h2, int h3)
		{
			return Tuple.CombineHashCodes(Tuple.CombineHashCodes(h1, h2), h3);
		}
		internal static int CombineHashCodes(int h1, int h2, int h3, int h4)
		{
			return Tuple.CombineHashCodes(Tuple.CombineHashCodes(h1, h2), Tuple.CombineHashCodes(h3, h4));
		}
		internal static int CombineHashCodes(int h1, int h2, int h3, int h4, int h5)
		{
			return Tuple.CombineHashCodes(Tuple.CombineHashCodes(h1, h2, h3, h4), h5);
		}
		internal static int CombineHashCodes(int h1, int h2, int h3, int h4, int h5, int h6)
		{
			return Tuple.CombineHashCodes(Tuple.CombineHashCodes(h1, h2, h3, h4), Tuple.CombineHashCodes(h5, h6));
		}
		internal static int CombineHashCodes(int h1, int h2, int h3, int h4, int h5, int h6, int h7)
		{
			return Tuple.CombineHashCodes(Tuple.CombineHashCodes(h1, h2, h3, h4), Tuple.CombineHashCodes(h5, h6, h7));
		}
		internal static int CombineHashCodes(int h1, int h2, int h3, int h4, int h5, int h6, int h7, int h8)
		{
			return Tuple.CombineHashCodes(Tuple.CombineHashCodes(h1, h2, h3, h4), Tuple.CombineHashCodes(h5, h6, h7, h8));
		}
		internal static int GetHashCode(object obj)
		{
			return System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode(obj);
		}
		#endregion
	}
	#endregion

	#region tuple 8 values
	internal class Tuple<t1, t2, t3, t4, t5, t6, t7, tRest> : Tuple<t1, t2, t3, t4, t5, t6, t7>
	{
		public Tuple()
			: base()
		{
		}
		public Tuple(t1 item1, t2 item2, t3 item3, t4 item4, t5 item5, t6 item6, t7 item7, tRest rest)
			: base(item1, item2, item3, item4, item5, item6, item7)
		{
			Rest = rest;
		}
		public tRest Rest { get; set; }
		public override bool Equals(object obj)
		{
			Tuple<t1, t2, t3, t4, t5, t6, t7, tRest> tuple = obj as Tuple<t1, t2, t3, t4, t5, t6, t7, tRest>;
			if (tuple != null)
			{
				return Tuple.EqualTupleFieldValues(Item1, tuple.Item1)
					&& Tuple.EqualTupleFieldValues(Item2, tuple.Item2)
					&& Tuple.EqualTupleFieldValues(Item3, tuple.Item3)
					&& Tuple.EqualTupleFieldValues(Item4, tuple.Item4)
					&& Tuple.EqualTupleFieldValues(Item5, tuple.Item5)
					&& Tuple.EqualTupleFieldValues(Item6, tuple.Item6)
					&& Tuple.EqualTupleFieldValues(Item7, tuple.Item7)
					&& Tuple.EqualTupleFieldValues(Rest, tuple.Rest);
			}
			return false;
		}
		public override int GetHashCode()
		{
			return Tuple.CombineHashCodes(Tuple.GetHashCode(Item1), Tuple.GetHashCode(Item2), Tuple.GetHashCode(Item3),
				Tuple.GetHashCode(Item4), Tuple.GetHashCode(Item5), Tuple.GetHashCode(Item6), Tuple.GetHashCode(Item7), Tuple.GetHashCode(Rest));
		}
	}
	#endregion

	#region tuple 7 values
	internal class Tuple<t1, t2, t3, t4, t5, t6, t7> : Tuple<t1, t2, t3, t4, t5, t6>
	{
		public Tuple()
			: base()
		{
		}
		public Tuple(t1 item1, t2 item2, t3 item3, t4 item4, t5 item5, t6 item6, t7 item7)
			: base(item1, item2, item3, item4, item5, item6)
		{
			Item7 = item7;
		}
		public t7 Item7 { get; set; }
		public override bool Equals(object obj)
		{
			Tuple<t1, t2, t3, t4, t5, t6, t7> tuple = obj as Tuple<t1, t2, t3, t4, t5, t6, t7>;
			if (tuple != null)
			{
				return Tuple.EqualTupleFieldValues(Item1, tuple.Item1)
					&& Tuple.EqualTupleFieldValues(Item2, tuple.Item2)
					&& Tuple.EqualTupleFieldValues(Item3, tuple.Item3)
					&& Tuple.EqualTupleFieldValues(Item4, tuple.Item4)
					&& Tuple.EqualTupleFieldValues(Item5, tuple.Item5)
					&& Tuple.EqualTupleFieldValues(Item6, tuple.Item6)
					&& Tuple.EqualTupleFieldValues(Item7, tuple.Item7);
			}
			return false;
		}
		public override int GetHashCode()
		{
			return Tuple.CombineHashCodes(Tuple.GetHashCode(Item1), Tuple.GetHashCode(Item2), Tuple.GetHashCode(Item3), Tuple.GetHashCode(Item4), Tuple.GetHashCode(Item5), Tuple.GetHashCode(Item6), Tuple.GetHashCode(Item7));
		}
	}
	#endregion

	#region tuple 6 values
	internal class Tuple<t1, t2, t3, t4, t5, t6> : Tuple<t1, t2, t3, t4, t5>
	{
		public Tuple()
			: base()
		{
		}
		public Tuple(t1 item1, t2 item2, t3 item3, t4 item4, t5 item5, t6 item6)
			: base(item1, item2, item3, item4, item5)
		{
			Item6 = item6;
		}
		public t6 Item6 { get; set; }
		public override bool Equals(object obj)
		{
			Tuple<t1, t2, t3, t4, t5, t6> tuple = obj as Tuple<t1, t2, t3, t4, t5, t6>;
			if (tuple != null)
			{
				return Tuple.EqualTupleFieldValues(Item1, tuple.Item1)
					&& Tuple.EqualTupleFieldValues(Item2, tuple.Item2)
					&& Tuple.EqualTupleFieldValues(Item3, tuple.Item3)
					&& Tuple.EqualTupleFieldValues(Item4, tuple.Item4)
					&& Tuple.EqualTupleFieldValues(Item5, tuple.Item5)
					&& Tuple.EqualTupleFieldValues(Item6, tuple.Item6);
			}
			return false;
		}
		public override int GetHashCode()
		{
			return Tuple.CombineHashCodes(Tuple.GetHashCode(Item1), Tuple.GetHashCode(Item2), Tuple.GetHashCode(Item3), Tuple.GetHashCode(Item4), Tuple.GetHashCode(Item5), Tuple.GetHashCode(Item6));
		}
	}
	#endregion

	#region tuple 5 values
	internal class Tuple<t1, t2, t3, t4, t5> : Tuple<t1, t2, t3, t4>
	{
		public Tuple()
			: base()
		{
		}
		public Tuple(t1 item1, t2 item2, t3 item3, t4 item4, t5 item5)
			: base(item1, item2, item3, item4)
		{
			Item5 = item5;
		}
		public t5 Item5 { get; set; }
		public override bool Equals(object obj)
		{
			Tuple<t1, t2, t3, t4, t5> tuple = obj as Tuple<t1, t2, t3, t4, t5>;
			if (tuple != null)
			{
				return Tuple.EqualTupleFieldValues(Item1, tuple.Item1)
					&& Tuple.EqualTupleFieldValues(Item2, tuple.Item2)
					&& Tuple.EqualTupleFieldValues(Item3, tuple.Item3)
					&& Tuple.EqualTupleFieldValues(Item4, tuple.Item4)
					&& Tuple.EqualTupleFieldValues(Item5, tuple.Item5);
			}
			return false;
		}
		public override int GetHashCode()
		{
			return Tuple.CombineHashCodes(Tuple.GetHashCode(Item1), Tuple.GetHashCode(Item2), Tuple.GetHashCode(Item3), Tuple.GetHashCode(Item4), Tuple.GetHashCode(Item5));
		}
	}
	#endregion

	#region tuple 4 values
	internal class Tuple<t1, t2, t3, t4> : Tuple<t1, t2, t3>
	{
		public Tuple()
			: base()
		{
		}
		public Tuple(t1 item1, t2 item2, t3 item3, t4 item4)
			: base(item1, item2, item3)
		{
			Item4 = item4;
		}
		public t4 Item4 { get; set; }
		public override bool Equals(object obj)
		{
			Tuple<t1, t2, t3, t4> tuple = obj as Tuple<t1, t2, t3, t4>;
			if (tuple != null)
			{
				return Tuple.EqualTupleFieldValues(Item1, tuple.Item1)
					&& Tuple.EqualTupleFieldValues(Item2, tuple.Item2)
					&& Tuple.EqualTupleFieldValues(Item3, tuple.Item3)
					&& Tuple.EqualTupleFieldValues(Item4, tuple.Item4);
			}
			return false;
		}
		public override int GetHashCode()
		{
			return Tuple.CombineHashCodes(Tuple.GetHashCode(Item1), Tuple.GetHashCode(Item2), Tuple.GetHashCode(Item3), Tuple.GetHashCode(Item4));
		}
	}
	#endregion

	#region tuple 3 values
	internal class Tuple<t1, t2, t3> : Tuple<t1, t2>
	{
		public Tuple()
			: base()
		{
		}
		public Tuple(t1 item1, t2 item2, t3 item3)
			: base(item1, item2)
		{
			Item3 = item3;
		}
		public t3 Item3 { get; set; }
		public override bool Equals(object obj)
		{
			Tuple<t1, t2, t3> tuple = obj as Tuple<t1, t2, t3>;
			if (tuple != null)
			{
				return Tuple.EqualTupleFieldValues(Item1, tuple.Item1)
					&& Tuple.EqualTupleFieldValues(Item2, tuple.Item2)
					&& Tuple.EqualTupleFieldValues(Item3, tuple.Item3);
			}
			return false;
		}
		public override int GetHashCode()
		{
			return Tuple.CombineHashCodes(Tuple.GetHashCode(Item1), Tuple.GetHashCode(Item2), Tuple.GetHashCode(Item3));
		}
	}
	#endregion

	#region 2 values
	internal class Tuple<t1, t2> : Tuple<t1>
	{
		public Tuple()
			: base()
		{
		}
		public Tuple(t1 item1, t2 item2)
			: base(item1)
		{
			Item2 = item2;
		}
		public t2 Item2 { get; set; }
		public override bool Equals(object obj)
		{
			Tuple<t1, t2> tuple = obj as Tuple<t1, t2>;
			if (tuple != null)
			{
				return Tuple.EqualTupleFieldValues(Item1, tuple.Item1)
					&& Tuple.EqualTupleFieldValues(Item2, tuple.Item2);
			}
			return false;
		}
		public override int GetHashCode()
		{
			return Tuple.CombineHashCodes(Tuple.GetHashCode(Item1), Tuple.GetHashCode(Item2));
		}
	}
	#endregion

	#region 1 values
	[SerializableAttribute]
	internal class Tuple<t1>
	{
		public Tuple()
		{
		}
		public Tuple(t1 item1)
		{
			Item1 = item1;
		}
		public t1 Item1
		{
			get;
			set;
		}
		public override bool Equals(object obj)
		{
			Tuple<t1> tuple = obj as Tuple<t1>;
			if (tuple != null)
			{
				return Tuple.EqualTupleFieldValues(Item1, tuple.Item1);
			}
			return false;
		}
		public override int GetHashCode()
		{
			return Tuple.GetHashCode(Item1);
		}
	}
	#endregion
}